//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <ddk.h>
#include <bulverde.h>
#include <tsc2302.h>
#include <ssp.h>
//#include <ostimer.h>
#include <intcbits.h>
#include <drvpub.h>
#include <display.h>
#include <display_def.h>
#include "pen.h"
#include "calibrate.h"

//#define DIRECT_HANDINPUT

#ifdef DIRECT_HANDINPUT
#include "handinput.h"
static BOOL s_bHandState = FALSE;
static ULONG s_uDirectHand = 0;
#endif

#if (_TEST_TYPE == 41)      /* Test for Runtime of ISR */
    #define SAMPLETIMES 50
    static ULONG ulPenIsrTime[SAMPLETIMES];
    static ULONG ulPenTimerIsrTime[SAMPLETIMES];
    static INT nPenIsrSampleCounter = 0;
    static INT nPenTimerIsrSampleCounter = 0;
#endif //_TEST_TYPE == 41

#if (_TEST_TYPE == 42)      /* Test for times of interrupt */
    static ULONG ulCounterOfPenIsr = 0;
    static ULONG ulCounterOfPenTimerIsr = 0;
#endif //_TEST_TYPE == 42

#if (_TEST_TYPE == 43)      /* Test for Runtime of IST */
    #define SAMPLETIMES 50
    static ULONG ulPenISTRunTime[SAMPLETIMES];
    static INT nPenISTSampleCounter = 0;
#endif //_TEST_TYPE == 43


//#define _DBGPEN

//#define OST_BASE_VIRTUAL    ((UINT32)v_PerifBase + OST_OFFSET)
//#define INTC_BASE_VIRTUAL   ((UINT32)v_PerifBase + INTC_OFFSET)
//
// OSSR bits are all sticky (write one to clear)
// Optimize macro with assignment, instead of ANDing)
//
#define TIMER_M0_INT_CLR(pOSSR) (pOSSR = OSSR_M0)
#define TIMER_M1_INT_CLR(pOSSR) (pOSSR = OSSR_M1)
#define TIMER_M2_INT_CLR(pOSSR) (pOSSR = OSSR_M2)
#define TIMER_M3_INT_CLR(pOSSR) (pOSSR = OSSR_M3)

#define TIMER_M0_INT_EN(pOIER)  (pOIER |= OIER_E0)
#define TIMER_M0_INT_DIS(pOIER) (pOIER &= ~OIER_E0)

#define TIMER_M1_INT_EN(pOIER)  (pOIER |= OIER_E1)
#define TIMER_M1_INT_DIS(pOIER) (pOIER &= ~OIER_E1)

#define TIMER_M2_INT_EN(pOIER)  (pOIER |= OIER_E2)
#define TIMER_M2_INT_DIS(pOIER) (pOIER &= ~OIER_E2)

#define TIMER_M3_INT_EN(pOIER)  (pOIER |= OIER_E3)
#define TIMER_M3_INT_DIS(pOIER) (pOIER &= ~OIER_E3)


// the cconfiguration of OS Timer register for pen
#define OST_CONFIG_FOR_PEN          (OST_INT_ENABLE | OST_PERIODIC_ENABLE \
                                        | OST_RESET_ENABLE | OST_1_32768OFSECOND_COUNTER)

//#define NEEDCALIBRATE

#define XLLP_GPIO_BIT_PWM_OUT0				( XLLP_BIT_16 )

CPen tpen;
HANDLE timerChannel;

UINT dir = TP_PEN_UP;
UINT xCoordinat = 0;
UINT yCoordinat = 0;

#define UnusedParameter(x) x = x

typedef union{
    struct{
        // [0]
        unsigned short     Res0_0: 1;
        unsigned short     PV: 3;
        unsigned short     CL: 2;
        unsigned short     AV: 2;
        unsigned short     RS: 2;
        unsigned short     AD: 4;
        unsigned short     STS: 1;
        unsigned short     PSM: 1;

        // [1]
        unsigned short     Res1_4000: 16;

        // [2]
        unsigned short     Res2_0: 15;
        unsigned short     DPD: 1;

        // [3]
        unsigned short     RFV: 1;
        unsigned short     PDN: 1;
        unsigned short     DL: 2;
        unsigned short     INT: 1;
        unsigned short     Res3_0: 11;

        // [4]
        unsigned short     Reset: 16;

        // [5]
        unsigned short     SNS: 3;
        unsigned short     PRE: 3;
        unsigned short     Res5_3FF: 10;

        // [6]
        unsigned short     NN: 4;
        unsigned short     AA: 4;
        unsigned short     PDC: 4;
        unsigned short     PCTE: 1;
        unsigned short     PLLO: 1;
        unsigned short     Res6_1: 1;
        unsigned short     SDAV: 1;
    }RegByName;

unsigned short RegByNumber[7];
}PAGE1_REG;

static PAGE1_REG Page1Reg;

#define AD_SAMPLE_STYLE                 (2<<10)     // (1<<10)      (2<<10)
#define READ_REG_NUM                    4           // (2)          (4)
static short g_PenData[READ_REG_NUM];
static unsigned long g_PenDavCounter;
static int g_SampleStart;

static IThread * s_penThd;
DzEvent s_penEvt;

void PEN_Init(void)
{
    Page1Reg.RegByNumber[0] = 0x4036|AD_SAMPLE_STYLE;
    Page1Reg.RegByNumber[1] = 0x0400;
    Page1Reg.RegByNumber[2] = 0x8000;
    Page1Reg.RegByNumber[3] = 0x0000;
    Page1Reg.RegByNumber[4] = 0xffff;
    Page1Reg.RegByNumber[5] = 0xffc0;
    Page1Reg.RegByNumber[6] = 0xffff;

    TSC_RegWrite(1, 0, &Page1Reg.RegByNumber[0], 1);
    DzDelay(10);
    TSC_RegWrite(1, 3, &Page1Reg.RegByNumber[3], 1);
    DzDelay(10);
}

void PEN_EnterSelfControlMode(void)
{
    // the first time, some more work must be done
    // this is because of the bug of tsc2302
    // to learn more, look for the errata
    int i;

    for(i=0;i<2;i++)
    {
        Page1Reg.RegByName.STS = 1;
        TSC_RegWrite(1, 0, (unsigned short*)(&(Page1Reg.RegByNumber[0])), 1);
        DzDelay(10);

        Page1Reg.RegByName.STS = 0;
        TSC_RegWrite(1, 0, (unsigned short*)(&(Page1Reg.RegByNumber[0])), 1);
        DzDelay(10);

        Page1Reg.RegByName.PSM = 1;
        TSC_RegWrite(1, 0, (unsigned short*)(&(Page1Reg.RegByNumber[0])), 1);

        DzDelay(10);
    }

//        IOP_INT_X_Enable(3, PD26_PEN_DAV);
    TSC_RegRead(0, 0, (unsigned short *)g_PenData, READ_REG_NUM);          // dummy read to read the 0xffff out
    DzDelay(1);
    TSC_RegRead(0, 0, (unsigned short *)g_PenData, READ_REG_NUM);          // dummy read to read the 0xffff out

    g_PenDavCounter = 0;
    g_SampleStart = 0;

    kprintf("The touch panel can work correctly now!\r\n");
}

#if 0
void Page1RegShow(PAGE1_REG *pPage1Reg, int mask)
{
    if(mask & (1<<0))
    {
        kprintf("0x%08x ", pPage1Reg->RegByNumber[0]);
	    kprintf("\r\n");
    }
    if(mask & (1<<1))
    {
        kprintf("0x%08x ", pPage1Reg->RegByNumber[1]);
        kprintf("\r\n");
    }
    if(mask & (1<<2))
    {
	    kprintf("0x%08x ", pPage1Reg->RegByNumber[2]);
	    kprintf("\r\n");
    }
    if(mask & (1<<3))
    {
	    kprintf("0x%08x ", pPage1Reg->RegByNumber[3]);
	    kprintf("\r\n");
    }
    if(mask & (1<<4))
    {
	    kprintf("0x%08x ", pPage1Reg->RegByNumber[4]);
	    kprintf("\r\n");
    }
    if(mask & (1<<5))
    {
	    kprintf("0x%08x ", pPage1Reg->RegByNumber[5]);
	    kprintf("\r\n");
    }
    if(mask & (1<<6))
    {
	    kprintf("0x%08x ", pPage1Reg->RegByNumber[6]);
	    kprintf("\r\n");
    }
}

int serial_read(void)
{
    if ( (BTLSR & LSR_DR) <=0)
        return -1;

    return BTRBR & 0xff;
}

//test pen
int tPENRead()
{
    int i;

    kprintf("Wait pen \r\n");

    while( 'q' != serial_read())
    {
        if((GPLR0 & (1<<14)) == 0)
        {
            kprintf("----------------\n");
        	//INTC_GPIO0_INT_EN(v_pICRegs->icmr);
        	kprintf("ICMR = %x\n", ICMR);
            kprintf("status: ICPR = %x\n", ICPR);

           TSC_RegRead(0, 0, (unsigned short *)g_PenData, READ_REG_NUM);

           kprintf("\r");
           for(i=0;i<READ_REG_NUM;i++)
           {
               kprintf("0x%08x\t", g_PenData[i]);
           }
           kprintf("\r\n");
        }
    }
    return 0;
}
#endif

#if defined(NEEDCALIBRATE)
extern DisplayContext *g_pdisCxt;
void DrawCrossXOR(int x, int y);
void Display_Resume(DisplayContext *pCxt, int lcdOn);
void BackLight_Open(DisplayContext *pCxt);
static int rand()
{
    static int state = 100;
    return state = (state * 1103515245 + 12345) & 0x7fff;
}
#endif

BOOL PenTest(void)
{
	SSP_Initial();

//  TSC_RegRead(1, 0, Page1Reg.RegByNumber, 7);
//	for(i=0; i<7; i++)
//	Page1RegShow(&Page1Reg, (1<<i));

    PEN_Init();

    PEN_EnterSelfControlMode();

//  TSC_RegRead(1, 0, Page1Reg.RegByNumber, 7);
//	for(i=0;i<7;i++)
//  Page1RegShow(&Page1Reg, (1<<i));

//test accuracy
//  int i = 20;
//  while('q' != serial_read()) {
//      DrawCrossXOR(i,i);
//      while('q' != serial_read()) {
//          ;
//      }
//      i += 20;
//      if (i > 200) break;
//  }
//
//(3638, 3752)    -> (10, 10)     --(10, 10)
//(933, 676)      -> (200, 300)   --(200, 300)
#ifdef NEEDCALIBRATE
    // Show crosses on LCD for calibration
    Display_Resume(g_pdisCxt, 1);
    BackLight_Open(g_pdisCxt);

    int ret;
	int i, j;
    WaitResult wr;

    ICMR &= ~(1<<10);//disable

    ret = TSC_RegRead(0, 0, (unsigned short *)g_PenData, READ_REG_NUM);
    kprintf("touch need revise, please click the touch red point");
    DrawCrossXOR(X1, Y1);
    GPSR0 |= (1<<14);           // clear GPIO status
    while((GPLR0 & (1<<14)) != 0) ;
    DzSleep(10, &wr);
    for(i = 0; i < 10 ; i++) {
        ret = TSC_RegRead(0, 0, (unsigned short *)g_PenData, READ_REG_NUM);
        kprintf("return %d, (%d, %d)\n", ret, g_PenData[0], g_PenData[1]);
    }
#if defined(_NEED_EXCHANGE)
    {
        short tmp;
        tmp = g_PenData[0];
        g_PenData[0] = g_PenData[1];
        g_PenData[1] = tmp;
    }
#endif

    x1 = g_PenData[0];
    y1 = g_PenData[1];

    kprintf("please click the touch red point again\n");
    DrawCrossXOR(X2, Y2);
    GPSR0 |= (1<<14);           // clear GPIO status
    while((GPLR0 & (1<<14)) != 0) ;
    DzSleep(10, &wr);
    for(i = 0; i < 10 ; i++) {
        ret = TSC_RegRead(0, 0, (unsigned short *)g_PenData, READ_REG_NUM);
        kprintf("return %d, (%d, %d)\n", ret, g_PenData[0], g_PenData[1]);
    }
#if defined(_NEED_EXCHANGE)
    {
        short tmp;
        tmp = g_PenData[0];
        g_PenData[0] = g_PenData[1];
        g_PenData[1] = tmp;
    }
#endif

    x2 = g_PenData[0];
    y2 = g_PenData[1];

    int X, Y;
    kprintf("(%d, %d)\t-> (%d, %d)\t", x1, y1, X1, Y1);
    GetDisplayPoint(x1, y1, &X, &Y);
    kprintf("--(%d, %d)\n", X, Y);

    kprintf("(%d, %d)\t-> (%d, %d)\t", x2, y2, X2, Y2);
    GetDisplayPoint(x2, y2, &X, &Y);
    kprintf("--(%d, %d)\n", X, Y);
#if 1
    kprintf("Verify:\n");
    for(i = 0; i < 2 ; i++) {
        int X = rand() % 240;
        int Y = rand() % 320;
        DrawCrossXOR(X, Y);
        GPSR0 |= (1<<14);           // clear GPIO status
        DzDelay(100);//digest
        unsigned long temp = GPLR0;
        while((GPLR0 & (1<<14)) != 0) ;
        kprintf("~~~~~GPLR0 %08x-->%08x\n", temp, GPLR0);
        DzSleep(10, &wr);
        for(j = 0; j < 10 ; j++) {
            ret = TSC_RegRead(0, 0, (unsigned short *)g_PenData, READ_REG_NUM);
            kprintf("return %d, (%d, %d)\n", ret, g_PenData[0], g_PenData[1]);
        }
#if defined(_NEED_EXCHANGE)
    {
        short tmp;
        tmp = g_PenData[0];
        g_PenData[0] = g_PenData[1];
        g_PenData[1] = tmp;
    }
#endif

        kprintf("return %d, (%d, %d)\t->(%d, %d)\t",
            ret, X, Y, g_PenData[0], g_PenData[1]);
        GetDisplayPoint(g_PenData[0], g_PenData[1], &X, &Y);
        kprintf("--(%d, %d)\n", X, Y);

    }
#endif
    return FALSE;
#endif

    return TRUE;
}

extern DisplayContext *g_pdisCxt;
//Frame buffer address
#define HwLcdBaseAddress    (g_pdisCxt->vaBasePlane)
// Pixels per row
#define HwLCDRowPixels      240
// Pixels per column
#define HwLCDColPixels      320
// lcd dispay mode, maybe 1/2/4/8 bits-per-pixel
#define HwLCDMode           16
#define HwLCDPixels                 (UINT)(HwLCDRowPixels*HwLCDColPixels)
#define LcdBufferSize               (UINT)HwLCDPixels * HwLCDMode / 8
void DrawCrossXOR(int x, int y)
{
    void *lcdPtr = (void*)HwLcdBaseAddress;
    int i;
    int dx, dy;
kprintf("DrawCrossXOR %d %d\n", x, y);
    if (x < 0 || x >= HwLCDRowPixels || y < 0 || y >= HwLCDColPixels) {
        return;
    }

    //clean screen
    memset(lcdPtr, 0, LcdBufferSize);

    dx = x-9;
    dy = y-9;
    for(i=0; i<19; i++)
    {
        *((unsigned short*)lcdPtr + (dy + i)*HwLCDRowPixels + x) = 0xffff;
        *((unsigned short*)lcdPtr + y*HwLCDRowPixels + (dx + i)) = 0xffff;
    }
}

int g_bInCalibrate = 0;
DzEvent   g_CaliEvent;
int GetCalibratedPos(/*InOut*/short *x, /*InOut*/short *y)
{
    if (g_bInCalibrate) {//pen calibrate op
        //kprintf("Raw (%d, %d)\n", *x, *y);
        return 0;//In calibrate
    }

    int X, Y;
    GetDisplayPoint((int)*x, (int)*y, &X, &Y);

    //kprintf("(%d, %d)\t-> (%d, %d)\n", (int)*x, (int)*y, X, Y);

	if(X<0) 	X = 0;
    if(X>239) 	X = 239;
    if(Y<0) 	Y = 0;
    if(Y>319) 	Y = 319;
    //out
    *x = X;
    *y = Y;
    return 0;//pen normal
}

//Same as gdi event
typedef struct DECL_PACKED __touch_pad {
    short dir;
    short x;
    short y;
}G_TOUCH_PAD, *PG_TOUCH_PAD;

ECode CPen::Read(
        /* [in] */ UINT64 u64Offset,
        /* [in] */ UINT uNumberOfBytesToRead,
        /* [out] */ EzByteBuf ebbData,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    if (ebbData.IsNull() || ebbData.GetCapacity() < (int)sizeof(G_TOUCH_PAD)) {
        return E_INVALID_ARGUMENT;
    }

    EzByteBuf_<16> ebbPenData;
    MOUSE_ST *pInfo = (MOUSE_ST *)(char *)ebbPenData;//source
    PG_TOUCH_PAD r = (PG_TOUCH_PAD)(char*)ebbData;  //dest

    WaitResult wr;
    m_Lock.Lock(&wr);

    ECode ec = g_pEventQueues->Read(EVENT_TOUCH, 16, &ebbPenData, ppCompletionEvent);
    if (FAILED(ec)) goto EXIT;

    //Convert
    r->dir = (short)(pInfo->dir&0xff);
    r->x = (short)pInfo->x;
    r->y = (short)pInfo->y;
	ebbData.SetUsed(sizeof(PG_TOUCH_PAD));

EXIT:
    m_Lock.Unlock();

    return ec;
}

ECode  CPen::Write(
        /* [in] */ UINT64 u64Offset,
        /* [in] */ EzByteBuf ebbData,
        /* [out] */ UINT * puNumberOfBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

void EnQueueProc(int eType, int nCode, void *pParam);
void OnMouseDownProc(int eType, int nCode, void *pParam)
{
    if (tpen.pt.dir != TP_PEN_DOWN) return;

    g_bInCalibrate++;
    g_CaliEvent.NotifyByIsr();

    return ;
}

void OnKeyCancelProc(int eType, int nCode, void *pParam)
{
    //KPD_DATA *pKey = (KPD_DATA *)pParam;
    //if (pKey->keycode == 0x89/*VK_PHONE_HANG_UP*/)
    {
        g_CaliEvent.NotifyByIsr();
    }
    return ;
}

ECode PenThread(void *arg);
ECode CPen::Control(
        /* [in] */ INT nControlCode,
        /* [in] */ EzByteBuf ebbInData,
        /* [out] */ EzByteBuf * pOutData,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    ECode ec = E_ACCESS_DENIED;

    switch(nControlCode) {
        case 0:
            break;
        case 1://Set SampleRate
            break;
        case 2: {
            int ret = SetCalibrationMatrix(5, (RefPoint *)(char *)ebbInData);
            if (0 == ret) ec = NOERROR;
            break;
        }
        case 3: {
            //Hook Touch & Keypad Event
            AddNotify(EVENT_TOUCH, (void*)OnMouseDownProc);
            AddNotify(EVENT_KEYPAD, (void*)OnKeyCancelProc);

            kprintf("<<<<<<<<<%d\n", g_bInCalibrate);
            g_bInCalibrate = 1;

            g_CaliEvent.Clear();
            WaitResult wr;
            g_CaliEvent.Wait(&wr, NULL);//wait for MouseDown or KeyCancel

            RefPoint P;
            P.x = P.y = P.X = P.Y = 0;
            if (g_bInCalibrate > 1/*CaliOK*/) {
                P.x = (int)tpen.pt.x;
                P.y = (int)tpen.pt.y;
                assert(pOutData->Capacity () >= (int)sizeof(RefPoint));
                pOutData->Copy(&P, sizeof(RefPoint));
                ec = NOERROR;
            }

            kprintf(">>>>>>>>return %x, Got Raw Coordinate (%d, %d)\n", ec, P.x, P.y);
            g_bInCalibrate = 0;

            //Restore Touch & Keypad Event Hook
            AddNotify(EVENT_TOUCH, (void*)EnQueueProc);
            AddNotify(EVENT_KEYPAD, (void*)EnQueueProc);
            break;
        }

#ifdef DIRECT_HANDINPUT
        case 4: {
            // Direct hand input support
            assert(ebbInData.GetCapacity() >= (int)sizeof(int));
            ec = HandInputOpen(*(int *)(char *)ebbInData);
            if (SUCCEEDED(ec)) s_bHandState = TRUE;
            break;
        }

        case 5:
            HandInputClose();
            s_bHandState = FALSE;
            break;

#endif
        case 6:
            PenTest();
            break;


#if (_TEST_TYPE == 41)
        case 4100:
			memcpy(pOutData->GetPayload(),
					ulPenIsrTime,
					SAMPLETIMES * sizeof(ULONG));
		    pOutData->SetUsed(SAMPLETIMES * sizeof(ULONG));
			ec = NOERROR;
            break;
        case 4101:
            memcpy(pOutData->GetPayload(),
					ulPenTimerIsrTime,
					SAMPLETIMES * sizeof(ULONG));
			pOutData->SetUsed(SAMPLETIMES * sizeof(ULONG));
			ec = NOERROR;
            break;
#endif //_TEST_TYPE == 41

#if (_TEST_TYPE == 42)
        case 4200:
            *(ULONG *)(char *)ebbOutData = ulCounterOfPenIsr;
            pOutData->SetUsed(sizeof(ULONG));
            ec = NOERROR;
            break;
        case 4201:
            *(ULONG *)(char *)ebbOutData = ulCounterOfPenTimerIsr;
            pOutData->SetUsed(sizeof(ULONG));
            ec = NOERROR;
            break;
#endif //_TEST_TYPE == 42

#if (_TEST_TYPE == 43)
        case 4300:
            memcpy(pOutData->GetPayload(),
					ulPenISTRunTime,
					SAMPLETIMES * sizeof(ULONG));
			pOutData->SetUsed(SAMPLETIMES * sizeof(ULONG));
			ec = NOERROR;
            break;
#endif //_TEST_TYPE == 43

        default:
            break;
    };

    return ec;
}



__inline void cwrite(unsigned char c)
{
    //BTTHR = c;
}

__inline void cwrite1(unsigned char c)
{
    BTTHR = c;
}

static int PenState = 0;
static UINT PreX = 0;
static UINT PreY = 0;
static UINT penstamp = 0;

int CheckDistance(UINT x, UINT y)
{
    UINT dx = (x > PreX)?(x-PreX):(PreX-x);
    UINT dy = (y > PreY)?(y-PreY):(PreY-y);

    //kprintf("x %d, y %d, PreX %d, PreY %d\n", dx, dy, PreX, PreY);

    if ((dx == 0) && (dy == 0)) {
        return 1;
    }
    if ((dx > 200) || (dy > 200)) {
        return 2;
    }
    if ((dx < 3) && (dy < 3)) {
        return 3;
    }

    return 0;
}

//returns the number of milliseconds since boot time.
static int GetTickCount()
{
    return OSCR0 * 3;//100ns
}

void CDECL PenIsr(void *pvDevice, BOOL *bArg)
{
#if (_TEST_TYPE == 41)
    ULONG uTimerStart = OSCR0;
#endif //_TEST_TYPE == 41


    GEDR0 |= (1<<14);           // clear GPIO Edge-detect status
    GPSR0 |= (1<<14);           // clear GPIO pin status
    s_penEvt.NotifyByIsr();


#if (_TEST_TYPE == 41)
    ULONG uTimerEnd = OSCR0;
    if (nPenIsrSampleCounter >= SAMPLETIMES) nPenIsrSampleCounter = 0;
    ulPenIsrTime[nPenIsrSampleCounter++] = \
                            (uTimerEnd >= uTimerStart) ? \
                            (uTimerEnd - uTimerStart) : \
                            ((ULONG)0xFFFFFFFF - uTimerStart + uTimerEnd);
#endif //_TEST_TYPE == 41

#if (_TEST_TYPE == 42)
    ulCounterOfPenIsr++;
#endif //_TEST_TYPE == 42
}

///////////////////////////////
// TEST CODE
static int s_nAudioUp = 0;
void PowerUpAudioCodec()
{
    cwrite1('p');
    s_nAudioUp++;
    s_penEvt.NotifyByIsr();
}


void PenReadData()
{
#if (_TEST_TYPE == 43)
    ULONG uTimerStart = OSCR0;
#endif //_TEST_TYPE == 43


    cwrite('@');

    CPen *pTP = &tpen;

#if 1
    if((GPLR0 & (1<<14)) != 0) {
        //kprintf("WARNING: (GPLR0 & (1<<14)) != 0 in PenIsr\n");
        cwrite1('n');
        return;
    }
#endif

    // pen down or move status
    int ret = 1;
    do {
        ret = TSC_RegRead(0, 0, (unsigned short *)g_PenData, READ_REG_NUM);
    }while(0);
    if (ret == 0) {
        PenTest(); // Init pen again because of hardware bug
    }

#if defined(_NEED_EXCHANGE)
    {
        short tmp;
        tmp = g_PenData[0];
        g_PenData[0] = g_PenData[1];
        g_PenData[1] = tmp;
    }
#endif

    GetCalibratedPos(&g_PenData[0], &g_PenData[1]);

     pTP->pt.x = xCoordinat = g_PenData[0];
     pTP->pt.y = yCoordinat = g_PenData[1];

     if(dir == TP_PEN_UP)
         pTP->pt.dir = dir =  TP_PEN_DOWN;
     else
         pTP->pt.dir = dir = TP_PEN_MOVE;

    if (dir == TP_PEN_MOVE && 0 != (ret=CheckDistance(pTP->pt.x, pTP->pt.y))) {
        if (ret == 3) {//maybe push
            if (penstamp == (UINT)-1) {
                ;
            }
            else if (penstamp == 0) {
                penstamp = GetTickCount();
            }
            else {
                if (GetTickCount() - penstamp >= 1000 * 10000/*1s*/) {
                    pTP->pt.dir = dir = 3/*PEN_PUSH*/;
#if defined(_DBGPEN)
        kprintf("**************************\n");
        kprintf("pen push\n");
        kprintf("[%x] x = %d, y = %d\n", pTP->pt.dir, pTP->pt.x, pTP->pt.y);
        kprintf("**************************\n");
#endif
                    cwrite1('P');
                    InputNotifyByIsr(EVENT_TOUCH, 0, &(pTP->pt));
                    penstamp = (UINT)-1;//bigbig enough

#ifdef DIRECT_HANDINPUT
        if (s_bHandState) HandInputReset(1);
#endif
                }
            }
        }
    }
    else {
#if defined(_DBGPEN)
        kprintf("**************************\n");
        if (dir == TP_PEN_DOWN)
            kprintf("pen down\n");
        else
            kprintf("pen move\n");
        kprintf("[%x] x = %d, y = %d\n", pTP->pt.dir, pTP->pt.x, pTP->pt.y);
        kprintf("**************************\n");
#endif

        cwrite('0');
        InputNotifyByIsr(EVENT_TOUCH, 0, &(pTP->pt));
        PreX = pTP->pt.x;
        PreY = pTP->pt.y;

        if (penstamp != (UINT)-1) penstamp = 0;//reset

#ifdef DIRECT_HANDINPUT
        if (s_bHandState) HandInputPutPoint((int)xCoordinat, (int)yCoordinat);
#endif
    }

    //Clear and enable pen timer interrupt
    TIMER_M1_INT_CLR(OSSR);

    OSMR1 = OSCR + 3250*80;//80ms for paintapp
    //
    // Enable interrupts on Match 1
    //
    TIMER_M1_INT_EN(OIER);

    PenState = 1;//touch



#if (_TEST_TYPE == 43)
    ULONG uTimerEnd = OSCR0;
    if (nPenISTSampleCounter >= SAMPLETIMES) nPenISTSampleCounter = 0;
    ulPenISTRunTime[nPenISTSampleCounter++] = \
                                (uTimerEnd >= uTimerStart) ? \
                                (uTimerEnd - uTimerStart) : \
                                ((ULONG)0xFFFFFFFF - uTimerStart + uTimerEnd);
#endif //_TEST_TYPE == 43

    return ;

}

void CDECL PenTimerIsr( irq_t irq, void *pvDevice, InterruptContext *pContext)
{
#if (_TEST_TYPE == 41)
    ULONG uTimerStart = OSCR0;
#endif //_TEST_TYPE == 41


    if (PenState == 1) {
        tpen.pt.dir = dir = TP_PEN_UP;
        tpen.pt.x = xCoordinat;
        tpen.pt.y = yCoordinat;
    #if defined(_DBGPEN)
        kprintf("**************************\n");
        kprintf("pen up\n");
        kprintf("[%x] x = %d, y = %d\n", tpen.pt.dir, tpen.pt.x, tpen.pt.y);
        kprintf("**************************\n");    // DrawCrossXOR(200, 200);
    #endif

        cwrite1('U');
        InputNotifyByIsr(EVENT_TOUCH, 0, &(tpen.pt));

#ifdef DIRECT_HANDINPUT
        if (s_bHandState) HandInputReset(0);
#endif
    }

    penstamp = 0;
    //Clear and disable the interrupt
    TIMER_M1_INT_CLR(OSSR);
    TIMER_M1_INT_DIS(OIER);

    PenState = 0;


#if (_TEST_TYPE == 41)
    ULONG uTimerEnd = OSCR0;
    if (nPenTimerIsrSampleCounter >= SAMPLETIMES) nPenTimerIsrSampleCounter = 0;
    ulPenTimerIsrTime[nPenTimerIsrSampleCounter++] = \
                                    (uTimerEnd >= uTimerStart) ? \
                                    (uTimerEnd - uTimerStart) : \
                                    ((ULONG)0xFFFFFFFF - uTimerStart + uTimerEnd);

#endif //_TEST_TYPE == 41

#if (_TEST_TYPE == 42)
    ulCounterOfPenTimerIsr++;
#endif //_TEST_TYPE == 42

    return;

}

ECode PenThread(void *arg)
{
    WaitResult wr;
    while (1) {
        s_penEvt.Wait(&wr, NULL);
        PenReadData();
    }
}

void CPen::Dispose()
{

}

ECode CPen::Initialize()
{
#if (_TEST_TYPE == 41)
    memset(ulPenIsrTime, 0, sizeof(ULONG) * SAMPLETIMES);
    memset(ulPenTimerIsrTime, 0, sizeof(ULONG) * SAMPLETIMES);
#endif //_TEST_TYPE == 41

#if (_TEST_TYPE == 43)
    memset(ulPenISTRunTime, 0, sizeof(ULONG) * SAMPLETIMES);
#endif //_TEST_TYPE == 43

    DzRegisterIsr(27/*OST_1*/, IPL7, (isr_t)PenTimerIsr, (void*)this);

    Drv_GpioInstall(14, (void*)this, (void *) PenIsr);
//    DzRegisterIsr(10, IPL4, (isr_t)PenIsr, (void*)this);

    return NOERROR;
}

EXTERN_C CPen *PenNew()
{
    CPen * pTP = &tpen;
    tpen.Initialize();

    return pTP;

}

EXTERN IDeviceDriver * CDECL CreateTouch(uint_t uDeviceNo, void *pvParameter)
{
    CPen *pPen = PenNew();
	/*
	 * Enable GPIO 14 for falling edge (Active Low) to signal the GPIO interrupt.
	 */
    GFER0 |= (1<<14);     //GEDR Power GPIO bits - write to clear, enable the edge detect

    PenTest();//Pen Initiliaze & calibrate
    kprintf("Touch Initiliaze & calibrate \n");

    ECode ec = DzCreateKernelThread(PenThread,
                (PVoid)pPen, CreateThreadFlag_System, ThreadPriorityRank_Normal, &s_penThd);

    if (FAILED(ec)) {
        kprintf("CreateKernelThread error\n");
        return NULL;
    }

    return pPen;
}

ELAPI _CProfile_GetInt32(AString appName, AString keyName, Int32 *pValue);
// type:
// 0      Init
// 1      Disable when set overlay2
// 2      Reenable when disable overlay2
EXTERN_C void PenHook(int type)
{
#ifdef DIRECT_HANDINPUT
    if (type == 0) {
        _CProfile_GetInt32("Driver", "DirectHand", &s_uDirectHand);
        if (s_uDirectHand) {
            kprintf("Open overlay1 DirectHand input Support. \n");
            HandInputOpen(0);
            s_bHandState = TRUE;
        }
    }

    if (s_uDirectHand) {
        if (type == 1) {
            HandInputClose();
            s_bHandState = FALSE;
        }
        else if (type == 2) {
            HandInputOpen(0);
            s_bHandState = TRUE;
        }
    }
#endif
}
